package com.xp.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xp.dto.flow.FlowDefinitionDTO;
import com.xp.dto.flow.FlowDefinitionRequest;
import com.xp.dto.flow.FlowQueryRequest;
import com.xp.dto.flow.StatusUpdateRequest;
import com.xp.entity.FlowDefinition;
import com.xp.service.FlowDefinitionService;
import com.xp.utils.Result;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 流程定义管理控制器
 *
 * @author xp
 * @since 2025-01-01
 */
@Slf4j
@RestController
@RequestMapping("/flow-definitions")
@RequiredArgsConstructor
@Validated
@Tag(name = "流程定义管理", description = "流程定义的增删改查、状态管理、版本控制等接口")
public class FlowDefinitionController {

    private final FlowDefinitionService flowDefinitionService;

    /**
     * 分页查询流程定义列表
     */
    @GetMapping("/page")
    @Operation(summary = "分页查询流程定义", description = "支持多条件筛选的流程定义分页查询")
    public Result<IPage<FlowDefinitionDTO>> getFlowDefinitionPage(
            @Parameter(description = "页码", required = true) @RequestParam(defaultValue = "1") Integer current,
            @Parameter(description = "每页大小", required = true) @RequestParam(defaultValue = "10") Integer size,
            @Parameter(description = "流程编码") @RequestParam(required = false) String flowCode,
            @Parameter(description = "流程名称") @RequestParam(required = false) String flowName,
            @Parameter(description = "流程分类") @RequestParam(required = false) String category,
            @Parameter(description = "状态列表") @RequestParam(required = false) List<Integer> statusList,
            @Parameter(description = "版本号") @RequestParam(required = false) String version,
            @Parameter(description = "应用名称") @RequestParam(required = false) String applicationName,
            @Parameter(description = "创建者ID") @RequestParam(required = false) Long creatorId,
            @Parameter(description = "创建时间开始") @RequestParam(required = false) String createTimeStart,
            @Parameter(description = "创建时间结束") @RequestParam(required = false) String createTimeEnd,
            @Parameter(description = "排序字段") @RequestParam(required = false) String sortField,
            @Parameter(description = "排序方式") @RequestParam(required = false) String sortOrder) {

        Page<FlowDefinition> page = new Page<>(current, size);

        FlowQueryRequest queryRequest = new FlowQueryRequest();
        queryRequest.setFlowCode(flowCode);
        queryRequest.setFlowName(flowName);
        queryRequest.setCategory(category);
        queryRequest.setStatusList(statusList);
        queryRequest.setVersion(version);
        queryRequest.setApplicationName(applicationName);
        queryRequest.setCreatorId(creatorId);

        // 处理时间字符串转换为LocalDateTime
        if (createTimeStart != null && !createTimeStart.trim().isEmpty()) {
            queryRequest.setCreateTimeStart(LocalDateTime.parse(createTimeStart));
        }
        if (createTimeEnd != null && !createTimeEnd.trim().isEmpty()) {
            queryRequest.setCreateTimeEnd(LocalDateTime.parse(createTimeEnd));
        }

        // 使用正确的方法名
        queryRequest.setOrderBy(sortField);
        queryRequest.setOrderDirection(sortOrder);

        return flowDefinitionService.getFlowDefinitionPage(page, queryRequest);
    }

    /**
     * 获取所有启用的流程定义
     */
    @GetMapping("/enabled")
    @Operation(summary = "获取启用流程定义", description = "获取所有状态为启用的流程定义列表")
    public Result<List<FlowDefinitionDTO>> getEnabledFlowDefinitions() {
        return flowDefinitionService.getEnabledFlowDefinitions();
    }

    /**
     * 根据ID获取流程定义详情
     */
    @GetMapping("/{id}")
    @Operation(summary = "获取流程定义详情", description = "根据流程定义ID获取详细信息")
    public Result<FlowDefinitionDTO> getFlowDefinitionById(
            @Parameter(description = "流程定义ID", required = true) @PathVariable Long id) {
        return flowDefinitionService.getFlowDefinitionById(id);
    }

    /**
     * 根据流程编码获取流程定义
     */
    @GetMapping("/code/{flowCode}")
    @Operation(summary = "根据编码获取流程定义", description = "根据流程编码获取流程定义信息")
    public Result<FlowDefinitionDTO> getFlowDefinitionByCode(
            @Parameter(description = "流程编码", required = true) @PathVariable String flowCode) {
        return flowDefinitionService.getFlowDefinitionByCode(flowCode);
    }

    /**
     * 根据流程编码和版本获取流程定义
     */
    @GetMapping("/code/{flowCode}/version/{version}")
    @Operation(summary = "根据编码和版本获取流程定义", description = "根据流程编码和版本号获取特定版本的流程定义")
    public Result<FlowDefinitionDTO> getFlowDefinitionByCodeAndVersion(
            @Parameter(description = "流程编码", required = true) @PathVariable String flowCode,
            @Parameter(description = "版本号", required = true) @PathVariable String version) {
        return flowDefinitionService.getFlowDefinitionByCodeAndVersion(flowCode, version);
    }

    /**
     * 根据分类获取流程定义列表
     */
    @GetMapping("/category/{category}")
    @Operation(summary = "根据分类获取流程定义", description = "根据流程分类获取流程定义列表")
    public Result<List<FlowDefinitionDTO>> getFlowDefinitionsByCategory(
            @Parameter(description = "流程分类", required = true) @PathVariable String category) {
        return flowDefinitionService.getFlowDefinitionsByCategory(category);
    }

    /**
     * 根据应用名称获取流程定义列表
     */
    @GetMapping("/application/{applicationName}")
    @Operation(summary = "根据应用获取流程定义", description = "根据应用名称获取流程定义列表")
    public Result<List<FlowDefinitionDTO>> getFlowDefinitionsByApplication(
            @Parameter(description = "应用名称", required = true) @PathVariable String applicationName) {
        return flowDefinitionService.getFlowDefinitionsByApplication(applicationName);
    }

    /**
     * 创建流程定义
     */
    @PostMapping
    @Operation(summary = "创建流程定义", description = "创建新的流程定义")
    public Result<Long> createFlowDefinition(@Valid @RequestBody FlowDefinitionRequest request) {
        return flowDefinitionService.createFlowDefinition(request);
    }

    /**
     * 更新流程定义
     */
    @PutMapping("/{id}")
    @Operation(summary = "更新流程定义", description = "更新指定的流程定义信息")
    public Result<Object> updateFlowDefinition(
            @Parameter(description = "流程定义ID", required = true) @PathVariable Long id,
            @Valid @RequestBody FlowDefinitionRequest request) {
        return flowDefinitionService.updateFlowDefinition(id, request);
    }

    /**
     * 删除流程定义
     */
    @DeleteMapping("/{id}")
    @Operation(summary = "删除流程定义", description = "删除指定的流程定义")
    public Result<Object> deleteFlowDefinition(
            @Parameter(description = "流程定义ID", required = true) @PathVariable Long id) {
        return flowDefinitionService.deleteFlowDefinition(id);
    }

    /**
     * 更新流程定义状态
     */
    @PutMapping("/{id}/status")
    @Operation(summary = "更新流程定义状态", description = "更新流程定义的启用/禁用状态")
    public Result<Object> updateFlowDefinitionStatus(
            @Parameter(description = "流程定义ID", required = true) @PathVariable Long id,
            @Valid @RequestBody StatusUpdateRequest request) {
        return flowDefinitionService.updateFlowDefinitionStatus(id, request);
    }

    /**
     * 发布流程定义
     */
    @PostMapping("/{id}/publish")
    @Operation(summary = "发布流程定义", description = "发布流程定义，使其可以被执行")
    public Result<Object> publishFlowDefinition(
            @Parameter(description = "流程定义ID", required = true) @PathVariable Long id) {
        return flowDefinitionService.publishFlowDefinition(id);
    }

    /**
     * 下线流程定义
     */
    @PostMapping("/{id}/unpublish")
    @Operation(summary = "下线流程定义", description = "下线流程定义，停止其执行")
    public Result<Object> unpublishFlowDefinition(
            @Parameter(description = "流程定义ID", required = true) @PathVariable Long id) {
        return flowDefinitionService.unpublishFlowDefinition(id);
    }

    /**
     * 复制流程定义
     */
    @PostMapping("/{id}/copy")
    @Operation(summary = "复制流程定义", description = "复制现有流程定义创建新的流程")
    public Result<Long> copyFlowDefinition(
            @Parameter(description = "流程定义ID", required = true) @PathVariable Long id,
            @Valid @RequestBody CopyFlowRequest request) {
        return flowDefinitionService.copyFlowDefinition(id, request.getNewFlowCode(), request.getNewFlowName());
    }

    /**
     * 获取流程版本列表
     */
    @GetMapping("/code/{flowCode}/versions")
    @Operation(summary = "获取流程版本列表", description = "获取指定流程编码的所有版本")
    public Result<List<String>> getFlowVersions(
            @Parameter(description = "流程编码", required = true) @PathVariable String flowCode) {
        return flowDefinitionService.getFlowVersions(flowCode);
    }

    /**
     * 创建流程版本
     */
    @PostMapping("/{id}/version")
    @Operation(summary = "创建流程版本", description = "基于现有流程定义创建新版本")
    public Result<Long> createFlowVersion(
            @Parameter(description = "流程定义ID", required = true) @PathVariable Long id,
            @Valid @RequestBody CreateVersionRequest request) {
        return flowDefinitionService.createFlowVersion(id, request.getVersion());
    }

    /**
     * 验证流程配置
     */
    @PostMapping("/validate")
    @Operation(summary = "验证流程配置", description = "验证流程定义的配置是否正确")
    public Result<Object> validateFlowConfig(@Valid @RequestBody ValidateFlowRequest request) {
        return flowDefinitionService.validateFlowConfig(
            request.getFlowDefinition(),
            request.getNodeDefinitions()
        );
    }

    /**
     * 获取流程定义统计信息
     */
    @GetMapping("/statistics")
    @Operation(summary = "获取流程定义统计", description = "获取流程定义的统计信息")
    public Result<Object> getFlowDefinitionStatistics() {
        return flowDefinitionService.getFlowDefinitionStatistics();
    }

    /**
     * 转换LogicFlow数据为LiteFlow规则
     */
    @PostMapping("/{id}/convert")
    @Operation(summary = "转换为LiteFlow规则", description = "将LogicFlow流程图数据转换为LiteFlow EL表达式")
    public Result<Object> convertToLiteFlow(
            @Parameter(description = "流程定义ID", required = true) @PathVariable Long id) {
        return flowDefinitionService.convertToLiteFlow(id);
    }

    /**
     * 预览LiteFlow EL表达式
     */
    @PostMapping("/preview-liteflow")
    @Operation(summary = "预览LiteFlow表达式", description = "预览LogicFlow数据转换后的LiteFlow EL表达式")
    public Result<Object> previewLiteFlowExpression(@RequestBody Object flowData) {
        return flowDefinitionService.previewLiteFlowExpression(flowData);
    }

    /**
     * 导出流程定义
     */
    @GetMapping("/{id}/export")
    @Operation(summary = "导出流程定义", description = "导出流程定义配置")
    public Result<Object> exportFlowDefinition(
            @Parameter(description = "流程定义ID", required = true) @PathVariable Long id) {
        return flowDefinitionService.exportFlowDefinition(id);
    }

    /**
     * 导入流程定义
     */
    @PostMapping("/import")
    @Operation(summary = "导入流程定义", description = "导入流程定义配置")
    public Result<Long> importFlowDefinition(@Valid @RequestBody ImportFlowRequest request) {
        return flowDefinitionService.importFlowDefinition(request.getFlowData());
    }

    /**
     * 保存流程设计数据
     */
    @PutMapping("/{id}/design")
    @Operation(summary = "保存流程设计", description = "保存流程设计器中的流程图数据")
    public Result<Object> saveFlowDesign(
            @Parameter(description = "流程定义ID", required = true) @PathVariable Long id,
            @Valid @RequestBody SaveFlowDesignRequest request) {
        return flowDefinitionService.saveFlowDesign(id, request.getFlowData());
    }

    /**
     * 复制流程请求DTO
     */
    public static class CopyFlowRequest {

        @NotBlank(message = "新流程编码不能为空")
        @Parameter(description = "新流程编码", required = true)
        private String newFlowCode;

        @NotBlank(message = "新流程名称不能为空")
        @Parameter(description = "新流程名称", required = true)
        private String newFlowName;

        // Getter and Setter methods
        public String getNewFlowCode() {
            return newFlowCode;
        }

        public void setNewFlowCode(String newFlowCode) {
            this.newFlowCode = newFlowCode;
        }

        public String getNewFlowName() {
            return newFlowName;
        }

        public void setNewFlowName(String newFlowName) {
            this.newFlowName = newFlowName;
        }
    }

    /**
     * 创建版本请求DTO
     */
    public static class CreateVersionRequest {

        @NotBlank(message = "版本号不能为空")
        @Parameter(description = "版本号", required = true)
        private String version;

        // Getter and Setter methods
        public String getVersion() {
            return version;
        }

        public void setVersion(String version) {
            this.version = version;
        }
    }

    /**
     * 验证流程请求DTO
     */
    public static class ValidateFlowRequest {

        @Parameter(description = "流程定义配置", required = true)
        private String flowDefinition;

        @Parameter(description = "节点定义配置")
        private String nodeDefinitions;

        // Getter and Setter methods
        public String getFlowDefinition() {
            return flowDefinition;
        }

        public void setFlowDefinition(String flowDefinition) {
            this.flowDefinition = flowDefinition;
        }

        public String getNodeDefinitions() {
            return nodeDefinitions;
        }

        public void setNodeDefinitions(String nodeDefinitions) {
            this.nodeDefinitions = nodeDefinitions;
        }
    }

    /**
     * 导入流程请求DTO
     */
    public static class ImportFlowRequest {

        @NotBlank(message = "流程数据不能为空")
        @Parameter(description = "流程定义数据", required = true)
        private String flowData;

        // Getter and Setter methods
        public String getFlowData() {
            return flowData;
        }

        public void setFlowData(String flowData) {
            this.flowData = flowData;
        }
    }

    /**
     * 保存流程设计请求DTO
     */
    public static class SaveFlowDesignRequest {

        @Parameter(description = "流程图数据", required = true)
        private Object flowData;

        // Getter and Setter methods
        public Object getFlowData() {
            return flowData;
        }

        public void setFlowData(Object flowData) {
            this.flowData = flowData;
        }
    }
}
